<?php
/***************************************************************
*  Copyright notice
*
*  (c) 1999-2008 Kasper Skaarhoj (kasperYYYY@typo3.com)
*  All rights reserved
*
*  This script is part of the TYPO3 project. The TYPO3 project is
*  free software; you can redistribute it and/or modify
*  it under the terms of the GNU General Public License as published by
*  the Free Software Foundation; either version 2 of the License, or
*  (at your option) any later version.
*
*  The GNU General Public License can be found at
*  http://www.gnu.org/copyleft/gpl.html.
*  A copy is found in the textfile GPL.txt and important notices to the license
*  from the author is found in LICENSE.txt distributed with these scripts.
*
*
*  This script is distributed in the hope that it will be useful,
*  but WITHOUT ANY WARRANTY; without even the implied warranty of
*  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
*  GNU General Public License for more details.
*
*  This copyright notice MUST APPEAR in all copies of the script!
***************************************************************/
/**
 * TSParser extension class to t3lib_TStemplate
 *
 * $Id: class.t3lib_tsparser_ext.php 4137 2008-09-16 19:24:13Z benni $
 * Contains functions for the TS module in TYPO3 backend
 *
 * @author	Kasper Skaarhoj <kasperYYYY@typo3.com>
 */
/**
 * [CLASS/FUNCTION INDEX of SCRIPT]
 *
 *
 *
 *  105: class t3lib_tsparser_ext extends t3lib_TStemplate
 *  191:     function flattenSetup($setupArray, $prefix, $resourceFlag)
 *  218:     function substituteConstants($all)
 *  231:     function substituteConstantsCallBack($matches)
 *  261:     function substituteCMarkers($all)
 *  284:     function generateConfig_constants()
 *  330:     function ext_getSetup($theSetup,$theKey)
 *  358:     function ext_getObjTree($arr, $depth_in, $depthData, $parentType='',$parentValue='', $alphaSort='0')
 *  463:     function lineNumberToScript($lnArr)
 *  494:     function makeHtmlspecialchars($theValue)
 *  507:     function ext_getSearchKeys($arr, $depth_in, $searchString, $keyArray)
 *  562:     function ext_getRootlineNumber($pid)
 *  580:     function ext_getTemplateHierarchyArr($arr,$depthData, $keyArray,$first=0)
 *  639:     function ext_process_hierarchyInfo($depthDataArr,&$pointer)
 *  670:     function ext_outputTS($config, $lineNumbers=0, $comments=0, $crop=0, $syntaxHL=0, $syntaxHLBlockmode=0)
 *  697:     function ext_fixed_lgd($string,$chars)
 *  713:     function ext_lnBreakPointWrap($ln,$str)
 *  726:     function ext_formatTS($input, $ln, $comments=1, $crop=0)
 *  765:     function ext_getFirstTemplate($id,$template_uid=0)
 *  785:     function ext_getAllTemplates($id)
 *  806:     function ext_compareFlatSetups($default)
 *  872:     function ext_categorizeEditableConstants($editConstArray)
 *  895:     function ext_getCategoryLabelArray()
 *  912:     function ext_getTypeData($type)
 *  953:     function ext_getTSCE_config($category)
 *  992:     function ext_getKeyImage($key)
 * 1002:     function ext_getTSCE_config_image($imgConf)
 * 1026:     function ext_resourceDims()
 * 1056:     function ext_readDirResources($path)
 * 1071:     function readDirectory($path,$type='file')
 * 1096:     function ext_fNandV($params)
 * 1114:     function ext_printFields($theConstants,$category)
 *
 *              SECTION: Processing input values
 * 1408:     function ext_regObjectPositions($constants)
 * 1423:     function ext_regObjects($pre)
 * 1468:     function ext_putValueInConf($key, $var)
 * 1491:     function ext_removeValueInConf($key)
 * 1507:     function ext_depthKeys($arr,$settings)
 * 1542:     function ext_procesInput($http_post_vars,$http_post_files,$theConstants,$tplRow)
 * 1666:     function upload_copy_file($typeDat,&$tplRow,$theRealFileName,$tmp_name)
 * 1715:     function ext_prevPageWithTemplate($id,$perms_clause)
 * 1731:     function ext_setStar($val)
 * 1743:     function ext_detectAndFixExtensionPrefix($value)
 *
 * TOTAL FUNCTIONS: 41
 * (This index is automatically created/updated by the extension "extdeveval")
 *
 */

require_once(PATH_t3lib.'class.t3lib_tstemplate.php');







/**
 * TSParser extension class to t3lib_TStemplate
 *
 * @author	Kasper Skaarhoj <kasperYYYY@typo3.com>
 * @package TYPO3
 * @subpackage t3lib
 */
class t3lib_tsparser_ext extends t3lib_TStemplate	{

	var $edit_divider = '###MOD_TS:EDITABLE_CONSTANTS###';		// This string is used to indicate the point in a template from where the editable constants are listed. Any vars before this point (if it exists though) is regarded as default values.
	var $HTMLcolorList = 'aqua,beige,black,blue,brown,fuchsia,gold,gray,green,lime,maroon,navy,olive,orange,purple,red,silver,tan,teal,turquoise,yellow,white';

		// internal
	var $categories = array(
		'basic' => array(),		// Constants of superior importance for the template-layout. This is dimensions, imagefiles and enabling of various features. The most basic constants, which you would almost always want to configure.
		'menu' => array(),		// Menu setup. This includes fontfiles, sizes, background images. Depending on the menutype.
		'content' => array(),	// All constants related to the display of pagecontent elements
		'page' => array(),		// General configuration like metatags, link targets
		'advanced' => array(),	// Advanced functions, which are used very seldomly.
		'all' => array()		// All constants are put here also!
	);		// This will be filled with the available categories of the current template.
	var $subCategories = array(
		// Standard categories:
		'enable' => Array('Enable features', 'a'),
		'dims' => Array('Dimensions, widths, heights, pixels', 'b'),
		'file' => Array('Files', 'c'),
		'typo'	=> Array('Typography', 'd'),
		'color' => Array('Colors', 'e'),
		'links' => Array('Links and targets', 'f'),
		'language' => Array('Language specific constants', 'g'),

		// subcategories based on the default content elements
		'cheader' => Array('Content: \'Header\'', 'ma'),
		'cheader_g' => Array('Content: \'Header\', Graphical', 'ma'),
		'ctext' => Array('Content: \'Text\'', 'mb'),
		'cimage' => Array('Content: \'Image\'', 'md'),
		'cbullets' => Array('Content: \'Bullet list\'', 'me'),
		'ctable' => Array('Content: \'Table\'', 'mf'),
		'cuploads' => Array('Content: \'Filelinks\'', 'mg'),
		'cmultimedia' => Array('Content: \'Multimedia\'', 'mh'),
		'cmailform' => Array('Content: \'Form\'', 'mi'),
		'csearch' => Array('Content: \'Search\'', 'mj'),
		'clogin' => Array('Content: \'Login\'', 'mk'),
		'csplash' => Array('Content: \'Textbox\'', 'ml'),
		'cmenu' => Array('Content: \'Menu/Sitemap\'', 'mm'),
		'cshortcut' => Array('Content: \'Insert records\'', 'mn'),
		'clist' => Array('Content: \'List of records\'', 'mo'),
		'cscript' => Array('Content: \'Script\'', 'mp'),
		'chtml' => Array('Content: \'HTML\'', 'mq')
	);
	var $resourceDimensions = array();
	var $dirResources = array();

	var $backend_info=1;

		// tsconstanteditor
	var $ext_inBrace=0;

		// tsbrowser
	var $tsbrowser_searchKeys = array();
	var $tsbrowser_depthKeys = array();
	var $constantMode='';
	var $regexMode='';
	var $fixedLgd='';
	var $resourceCheck=0;
	var $ext_lineNumberOffset=0;
	var $ext_localGfxPrefix='';
	var $ext_localWebGfxPrefix='';
	var $ext_expandAllNotes=0;
	var $ext_noPMicons=0;
	var $ext_noSpecialCharsOnLabels=0;
	var $ext_listOfTemplatesArr=array();
	var $ext_lineNumberOffset_mode='';
	var $ext_dontCheckIssetValues=0;	// Dont change...
	var $ext_noCEUploadAndCopying=0;
	var $ext_printAll=0;
	var $ext_CEformName='forms[0]';
	var $ext_defaultOnlineResourceFlag=0;
	var $doNotSortCategoriesBeforeMakingForm = FALSE;

		// ts analyzer
	var $templateTitles=array();


	/**
	 * This flattens a hierarchical setuparray to $this->flatSetup
	 * The original function fetched the resource-file if any ('file.'). This functions doesn't.
	 *
	 * @param	[type]		$setupArray: ...
	 * @param	[type]		$prefix: ...
	 * @param	[type]		$resourceFlag: ...
	 * @return	[type]		...
	 */
	function flattenSetup($setupArray, $prefix, $resourceFlag)	{
		if (is_array($setupArray))	{
			$this->getFileName_backPath=PATH_site;		// Setting absolute prefixed path for relative resources.
			reset($setupArray);
			while(list($key,$val)=each($setupArray))	{
				if ($prefix || substr($key,0,16)!='TSConstantEditor')	{		// We don't want 'TSConstantEditor' in the flattend setup.
					if (is_array($val))	{
						$this->flattenSetup($val,$prefix.$key, ($key=='file.'));
					} elseif ($resourceFlag && $this->resourceCheck) {
						$this->flatSetup[$prefix.$key] = $this->getFileName($val);
						if ($this->removeFromGetFilePath && substr($this->flatSetup[$prefix.$key],0,strlen($this->removeFromGetFilePath))==$this->removeFromGetFilePath)	{
							$this->flatSetup[$prefix.$key] = substr($this->flatSetup[$prefix.$key],strlen($this->removeFromGetFilePath));
						}
					} else {
						$this->flatSetup[$prefix.$key] = $val;
					}
				}
			}
		}
	}

	/**
	 * [Describe function...]
	 *
	 * @param	[type]		$all: ...
	 * @return	[type]		...
	 */
	function substituteConstants($all)	{
		$this->Cmarker = substr(md5(uniqid('')),0,6);

		return preg_replace_callback('/\{\$(.[^}]+)\}/', array($this, 'substituteConstantsCallBack'), $all);
	}

	/**
	 * Call back method for preg_replace_callback in substituteConstants
	 *
	 * @param	array		Regular expression matches
	 * @return	string		Replacement
	 * @see substituteConstants()
	 */
	function substituteConstantsCallBack($matches) {
		switch($this->constantMode) {
			case 'const':
				$ret_val =  isset($this->flatSetup[$matches[1]]) && !is_array($this->flatSetup[$matches[1]]) ?
							'##'.$this->Cmarker.'_B##'.$matches[0].'##'.$this->Cmarker.'_E##' :
							$matches[0];
				break;
			case 'subst':
				$ret_val =  isset($this->flatSetup[$matches[1]]) && !is_array($this->flatSetup[$matches[1]]) ?
							'##'.$this->Cmarker.'_B##'.$this->flatSetup[$matches[1]].'##'.$this->Cmarker.'_E##' :
							$matches[0];
				break;
			case 'untouched':
				$ret_val = $matches[0];
				break;
			default:
				$ret_val = 	isset($this->flatSetup[$matches[1]]) && !is_array($this->flatSetup[$matches[1]]) ?
							$this->flatSetup[$matches[1]] :
							$matches[0];
		}

		return $ret_val;
	}

	/**
	 * [Describe function...]
	 *
	 * @param	[type]		$all: ...
	 * @return	[type]		...
	 */
	function substituteCMarkers($all)	{
		switch($this->constantMode)	{
			case 'const':
				$all = str_replace('##'.$this->Cmarker.'_B##', '<font color="green"><B>', $all);
				$all = str_replace('##'.$this->Cmarker.'_E##', '</b></font>', $all);
			break;
			case 'subst':
				$all = str_replace('##'.$this->Cmarker.'_B##', '<font color="green"><B>', $all);
				$all = str_replace('##'.$this->Cmarker.'_E##', '</b></font>', $all);
			break;
			default:
				$all = $all;
			break;
		}
		return $all;
	}

	/**
	 * Parses the constants in $this->const with respect to the constant-editor in this module.
	 * In particular comments in the code are registered and the edit_divider is taken into account.
	 *
	 * @return	[type]		...
	 */
	function generateConfig_constants()	{
			// These vars are also set lateron...
		$this->setup['resources'] = $this->resources;
		$this->setup['sitetitle'] = $this->sitetitle;

			// parse constants
		$constants = t3lib_div::makeInstance('t3lib_TSparser');
		$constants->regComments=1;		// Register comments!
		$constants->setup = $this->const;
		$constants->setup = $this->mergeConstantsFromPageTSconfig($constants->setup);

		$matchObj = t3lib_div::makeInstance('t3lib_matchCondition');
		$matchObj->matchAll=1;		// Matches ALL conditions in TypoScript

		$c=0;
		$cc=count($this->constants);
		reset($this->constants);
		while (list(,$str)=each($this->constants))	{
			$c++;
			if ($c==$cc)	{
				if (strstr($str,$this->edit_divider))	{
					$parts = explode($this->edit_divider,$str,2);
					$str=$parts[1];
					$constants->parse($parts[0],$matchObj);
				}
				$this->flatSetup = Array();
				$this->flattenSetup($constants->setup,'','');
				$defaultConstants=$this->flatSetup;
			}
			$constants->parse($str,$matchObj);
		}

		$this->flatSetup = Array();
		$this->flattenSetup($constants->setup,'','');
		$this->setup['constants'] = $constants->setup;

		return $this->ext_compareFlatSetups($defaultConstants);
	}

	/**
	 * [Describe function...]
	 *
	 * @param	[type]		$theSetup: ...
	 * @param	[type]		$theKey: ...
	 * @return	[type]		...
	 */
	function ext_getSetup($theSetup,$theKey)	{
		$parts = explode('.',$theKey,2);
		if (strcmp($parts[0],'') && is_array($theSetup[$parts[0].'.']))	{
			if (strcmp(trim($parts[1]),''))	{
				return $this->ext_getSetup($theSetup[$parts[0].'.'],trim($parts[1]));
			} else {
				return array($theSetup[$parts[0].'.'], $theSetup[$parts[0]]);
			}
		} else {
			if (strcmp(trim($theKey),''))	{
				return array(array(),$theSetup[$theKey]);
			} else {
				return array($theSetup,'');
			}
		}
	}

	/**
	 * [Describe function...]
	 *
	 * @param	[type]		$arr: ...
	 * @param	[type]		$depth_in: ...
	 * @param	[type]		$depthData: ...
	 * @param	[type]		$parentType: ...
	 * @param	[type]		$parentValue: ...
	 * @param	boolean		$alphaSort sorts the array keys / tree by alphabet when set to 1
	 * @return	[type]		...
	 */
	function ext_getObjTree($arr, $depth_in, $depthData, $parentType='',$parentValue='', $alphaSort='0')	{
		$HTML='';
		$a=0;

		reset($arr);
		if($alphaSort == '1')	{
			ksort($arr);
		}
		$keyArr_num=array();
		$keyArr_alpha=array();
		while (list($key,)=each($arr))	{
			if (substr($key,-2)!='..')	{	// Don't do anything with comments / linenumber registrations...
				$key=ereg_replace('\.$','',$key);
				if (substr($key,-1)!='.')	{
					if (t3lib_div::testInt($key))	{
						$keyArr_num[$key]=$arr[$key];
					} else {
						$keyArr_alpha[$key]=$arr[$key];
					}
				}
			}
		}
		ksort($keyArr_num);
		$keyArr=$keyArr_num+$keyArr_alpha;
		reset($keyArr);
		$c=count($keyArr);
		if ($depth_in)	{$depth_in = $depth_in.'.';}

		while (list($key,)=each($keyArr))	{
			$a++;
			$depth=$depth_in.$key;
			if ($this->bType!='const' || substr($depth,0,1)!='_')	{		// this excludes all constants starting with '_' from being shown.
				$goto = substr(md5($depth),0,6);
				$deeper = (is_array($arr[$key.'.']) && ($this->tsbrowser_depthKeys[$depth] || $this->ext_expandAllNotes)) ? 1 : 0;
				$PM = 'join';
				$LN = ($a==$c)?'blank':'line';
				$BTM = ($a==$c)?'bottom':'';
				$PM = is_array($arr[$key.'.']) && !$this->ext_noPMicons ? ($deeper ? 'minus':'plus') : 'join';

				$HTML.=$depthData;
				$theIcon='<img src="'.$GLOBALS['BACK_PATH'].'gfx/ol/'.$PM.$BTM.'.gif" width="18" height="16" align="top" border="0" alt="" />';
				if ($PM=='join')	{
					$HTML.=$theIcon;
				} else {
					$aHref='index.php?id='.$GLOBALS['SOBE']->id.'&tsbr['.$depth.']='.($deeper?0:1).'#'.$goto;
					$HTML.='<a name="'.$goto.'" href="'.htmlspecialchars($aHref).'">'.$theIcon.'</a>';
				}

				$label = $key;
				if (t3lib_div::inList('types,resources,sitetitle',$depth) && $this->bType=='setup')	{		// Read only...
					$label='<font color="#666666">'.$label.'</font>';
				} else {
					if ($this->linkObjects)	{
						$aHref = 'index.php?id='.$GLOBALS['SOBE']->id.'&sObj='.$depth;
						if ($this->bType!='const')	{
							$ln = is_array($arr[$key.'.ln..']) ? 'Defined in: '.$this->lineNumberToScript($arr[$key.'.ln..']) : 'N/A';
						} else {
							$ln = '';
						}

						if ($this->tsbrowser_searchKeys[$depth] & 4)	{ $label = '<b><font color="red">'.$label.'</font></b>'; }	// The key has matched the search string
						$label = '<a href="'.htmlspecialchars($aHref).'" title="'.htmlspecialchars($ln).'">'.$label.'</a>';
					}
				}

				$HTML.='['.$label.']';

				if (isset($arr[$key]))	{
					$theValue = $arr[$key];
					if ($this->fixedLgd)	{
						$imgBlocks = ceil(1+strlen($depthData)/77);
						$lgdChars = 68-ceil(strlen('['.$key.']')*0.8)-$imgBlocks*3;
						$theValue = $this->ext_fixed_lgd($theValue,$lgdChars);
					}
					if ($this->tsbrowser_searchKeys[$depth] & 2)	{	// The value has matched the search string
						$HTML.='&nbsp;=&nbsp;<b><font color="red">'.$this->makeHtmlspecialchars($theValue).'</font></b>';
					} else {
						$HTML.='&nbsp;=&nbsp;<b>'.$this->makeHtmlspecialchars($theValue).'</b>';
					}
					if ($this->ext_regComments && isset($arr[$key.'..']))	{
						$comment = $arr[$key.'..'];
						if (!preg_match('/### <INCLUDE_TYPOSCRIPT:.*/', $comment)) {	// Skip INCLUDE_TYPOSCRIPT comments, they are almost useless
							$comment = preg_replace('/[\r\n]/', ' ', $comment);	// Remove linebreaks, replace with ' '
							$comment = preg_replace('/[#\*]{2,}/', '', $comment);	// Remove # and * if more than twice in a row
							$comment = preg_replace('/^[#\*\s]+/', '# ', $comment);	// Replace leading # (just if it exists) and add it again. Result: Every comment should be prefixed by a '#'.
							$comment = $this->makeHtmlspecialchars($comment);	// Masking HTML Tags: Replace < with &lt; and > with &gt; 
							$HTML.= ' <span class="comment">'.trim($comment).'</span>';
						}
					}
				}
				$HTML.='<br />';

				if ($deeper)	{
					$HTML.=$this->ext_getObjTree($arr[$key.'.'], $depth, $depthData.'<img src="'.$GLOBALS['BACK_PATH'].'gfx/ol/'.$LN.'.gif" width="18" height="16" align="top" alt="" />', '' /* not used: $validate_info[$key] */, $arr[$key], $alphaSort);
				}
			}
		}
		return $HTML;
	}

	/**
	 * [Describe function...]
	 *
	 * @param	[type]		$lnArr: ...
	 * @return	[type]		...
	 */
	function lineNumberToScript($lnArr)	{
		if (!is_array($this->lnToScript))	{
			$this->lnToScript = array();
			$c=1;
			$c+=substr_count($GLOBALS['TYPO3_CONF_VARS']['FE']['defaultTypoScript_setup'],chr(10))+2;
			$this->lnToScript[$c] = '[Default]';

			foreach($this->hierarchyInfoToRoot as $info)	{
				$c+=$info['configLines']+1;
				$this->lnToScript[$c] = $info['title'];
			}
		}

		foreach($lnArr as $k => $ln)	{
			foreach($this->lnToScript as $endLn => $title)	{
				if ($endLn >= intval($ln))	{
					$lnArr[$k] = '"'.$title.'", '.$ln;
					break;
				}
			}
		}

		return implode('; ',$lnArr);
	}

	/**
	 * [Describe function...]
	 *
	 * @param	[type]		$theValue: ...
	 * @return	[type]		...
	 */
	function makeHtmlspecialchars($theValue){
		return $this->ext_noSpecialCharsOnLabels ? $theValue : htmlspecialchars($theValue);
	}

	/**
	 * [Describe function...]
	 *
	 * @param	[type]		$arr: ...
	 * @param	[type]		$depth_in: ...
	 * @param	[type]		$searchString: ...
	 * @param	[type]		$keyArray: ...
	 * @return	[type]		...
	 */
	function ext_getSearchKeys($arr, $depth_in, $searchString, $keyArray)		{
		reset($arr);
		$keyArr=array();
		while (list($key,)=each($arr))	{
			$key=ereg_replace('\.$','',$key);
			if (substr($key,-1)!='.')	{
				$keyArr[$key]=1;
			}
		}
		reset($keyArr);
		$c=count($keyArr);
		if ($depth_in)	{ $depth_in = $depth_in.'.'; }
		while (list($key,)=each($keyArr))	{
			$depth=$depth_in.$key;
			$deeper = is_array($arr[$key.'.']);

			if ($this->regexMode)	{
				if (ereg($searchString,$arr[$key]))	{	// The value has matched
					$this->tsbrowser_searchKeys[$depth]+=2;
				}
				if (ereg($searchString,$key))	{		// The key has matched
					$this->tsbrowser_searchKeys[$depth]+=4;
				}
				if (ereg($searchString,$depth_in))	{	// Just open this subtree if the parent key has matched the search
					$this->tsbrowser_searchKeys[$depth]=1;
				}
			} else {
				if (stristr($arr[$key],$searchString))	{	// The value has matched
					$this->tsbrowser_searchKeys[$depth]+=2;
				}
				if (stristr($key,$searchString))	{	// The key has matches
					$this->tsbrowser_searchKeys[$depth]+=4;
				}
				if (stristr($depth_in,$searchString))	{	// Just open this subtree if the parent key has matched the search
					$this->tsbrowser_searchKeys[$depth]=1;
				}
			}

			if ($deeper)	{
				$cS = count($this->tsbrowser_searchKeys);
				$keyArray = $this->ext_getSearchKeys($arr[$key.'.'], $depth, $searchString, $keyArray);
				if ($cS != count($this->tsbrowser_searchKeys))	{
					$keyArray[$depth]=1;
				}
			}
		}
		return $keyArray;
	}

	/**
	 * [Describe function...]
	 *
	 * @param	[type]		$pid: ...
	 * @return	[type]		...
	 */
	function ext_getRootlineNumber($pid)	{
		if ($pid && is_array($GLOBALS['rootLine']))	{
			reset($GLOBALS['rootLine']);
			while(list($key,$val)=each($GLOBALS['rootLine']))	{
				if ($val['uid']==$pid)	return $key;
			}
		}
	}

	/**
	 * [Describe function...]
	 *
	 * @param	[type]		$arr: ...
	 * @param	[type]		$depthData: ...
	 * @param	[type]		$keyArray: ...
	 * @param	[type]		$first: ...
	 * @return	[type]		...
	 */
	function ext_getTemplateHierarchyArr($arr,$depthData, $keyArray,$first=0)	{
		reset($arr);
		$keyArr=array();
		while (list($key,)=each($arr))	{
			$key=ereg_replace('\.$','',$key);
			if (substr($key,-1)!='.')	{
				$keyArr[$key]=1;
			}
		}
		reset($keyArr);
		$a=0;
		$c=count($keyArr);
		while (list($key,)=each($keyArr))	{
			$HTML='';
			$a++;
			$deeper = is_array($arr[$key.'.']);
			$row=$arr[$key];

			$PM = 'join';
			$LN = ($a==$c)?'blank':'line';
			$BTM = ($a==$c)?'top':'';
			$PM = 'join';

			$HTML.=$depthData;
			$icon = substr($row['templateID'],0,3)=='sys' ? t3lib_iconWorks::getIcon('sys_template',array('root'=>$row['root'])) :
							(substr($row['templateID'],0,6)=='static' ? t3lib_iconWorks::getIcon('static_template',array()) : 'gfx/i/default.gif');
			$alttext= '['.$row['templateID'].']';
			$alttext.= $row['pid'] ? ' - '.t3lib_BEfunc::getRecordPath($row['pid'],$GLOBALS['SOBE']->perms_clause,20) : '';
			if (in_array($row['templateID'],$this->clearList_const) || in_array($row['templateID'],$this->clearList_setup))	{
				$A_B='<a href="index.php?id='.$GLOBALS['SOBE']->id.'&template='.$row['templateID'].'">';
				$A_E='</a>';
			} else {
				$A_B='';
				$A_E='';
			}
			$HTML.=($first?'':'<IMG src="'.$GLOBALS['BACK_PATH'].'gfx/ol/'.$PM.$BTM.'.gif" width="18" height="16" align="top" border=0>').'<img ' . t3lib_iconWorks::skinImg($GLOBALS['BACK_PATH'], $icon) . ' align="top" title="'.$alttext.'" /> '.$A_B.t3lib_div::fixed_lgd_cs($row['title'],$GLOBALS['BE_USER']->uc['titleLen']).$A_E.'&nbsp;&nbsp;';
			$RL = $this->ext_getRootlineNumber($row['pid']);
			$keyArray[] = '<tr>
							<td nowrap>'.$HTML.'</td>
							<td align=center>'.($row['root']?'<b>X</b>':'').'&nbsp;&nbsp;</td>
							<td align=center'.$row['bgcolor_setup'].'>'.fw(($row['clConf']?'<b>X</b>':'').'&nbsp;&nbsp;').'</td>
							<td align=center'.$row['bgcolor_const'].'>'.fw(($row['clConst']?'<b>X</b>':'').'&nbsp;&nbsp;').'</td>
							<td>'.($row['pid']?'&nbsp;'.$row['pid'].(strcmp($RL,'')?' ('.$RL.')':'').'&nbsp;&nbsp;':'').'</td>
							<td>'.($row['next']?'&nbsp;'.$row['next'].'&nbsp;&nbsp;':'').'</td>
						</tr>';
			if ($deeper)	{
				$keyArray = $this->ext_getTemplateHierarchyArr($arr[$key.'.'], $depthData.($first?'':'<IMG src="'.$GLOBALS['BACK_PATH'].'gfx/ol/'.$LN.'.gif" width="18" height="16" align="top">'), $keyArray);
			}
		}
		return $keyArray;
	}

	/**
	 * [Describe function...]
	 *
	 * @param	[type]		$depthDataArr: ...
	 * @param	[type]		$pointer: ...
	 * @return	[type]		...
	 */
	function ext_process_hierarchyInfo($depthDataArr,&$pointer)	{
		$parent = $this->hierarchyInfo[$pointer-1]['templateParent'];
		while ($pointer>0 && $this->hierarchyInfo[$pointer-1]['templateParent']==$parent)	{
			$pointer--;
			$row = $this->hierarchyInfo[$pointer];

			$depthDataArr[$row['templateID']]=$row;
			$depthDataArr[$row['templateID']]['bgcolor_setup'] = isset($this->clearList_setup_temp[$row['templateID']])?' class="bgColor5"':'';
			$depthDataArr[$row['templateID']]['bgcolor_const'] = isset($this->clearList_const_temp[$row['templateID']])?' class="bgColor5"':'';
			unset($this->clearList_setup_temp[$row['templateID']]);
			unset($this->clearList_const_temp[$row['templateID']]);
			$this->templateTitles[$row['templateID']]=$row['title'];

			if ($row['templateID']==$this->hierarchyInfo[$pointer-1]['templateParent'])	{
				$depthDataArr[$row['templateID'].'.'] = $this->ext_process_hierarchyInfo(array(), $pointer);
			}
		}
		return $depthDataArr;
	}

	/**
	 * [Describe function...]
	 *
	 * @param	[type]		$config: ...
	 * @param	[type]		$lineNumbers: ...
	 * @param	[type]		$comments: ...
	 * @param	[type]		$crop: ...
	 * @param	[type]		$syntaxHL: ...
	 * @param	[type]		$syntaxHLBlockmode: ...
	 * @return	[type]		...
	 */
	function ext_outputTS($config, $lineNumbers=0, $comments=0, $crop=0, $syntaxHL=0, $syntaxHLBlockmode=0)	{
		$all='';
		reset($config);
		while (list(,$str)=each($config))	{
			$all .= chr(10) .'[GLOBAL]' . chr(10) . $str;
		}

		if ($syntaxHL)	{
			$all = ereg_replace('^[^'.chr(10).']*.','',$all);
			$all = chop($all);
			$tsparser = t3lib_div::makeInstance('t3lib_TSparser');
			$tsparser->lineNumberOffset=$this->ext_lineNumberOffset+1;
			return $tsparser->doSyntaxHighlight($all,$lineNumbers?array($this->ext_lineNumberOffset+1):'',$syntaxHLBlockmode);
		} else {
			return $this->ext_formatTS($all,$lineNumbers,$comments,$crop);
		}
	}

	/**
	 * Returns a new string of max. $chars lenght
	 * If the string is longer, it will be truncated and prepended with '...'
	 * $chars must be an integer of at least 4
	 *
	 * @param	[type]		$string: ...
	 * @param	[type]		$chars: ...
	 * @return	[type]		...
	 */
	function ext_fixed_lgd($string,$chars)	{
		if ($chars >= 4)	{
			if(strlen($string)>$chars)  {
				if(strlen($string)>24 && substr($string,0,12) == '##'.$this->Cmarker.'_B##') {
					return '##'.$this->Cmarker.'_B##'.t3lib_div::fixed_lgd_cs(substr($string,12,-12), $chars-3).'##'.$this->Cmarker.'_E##';
				} else {
					return t3lib_div::fixed_lgd_cs($string, $chars-3);
				}
			}
		}
		return $string;
	}

	/**
	 * [Describe function...]
	 *
	 * @param	[type]		$ln: ...
	 * @param	[type]		$str: ...
	 * @return	[type]		...
	 */
	function ext_lnBreakPointWrap($ln,$str)	{
		return '<a href="#" onClick="return brPoint('.$ln.','.($this->ext_lineNumberOffset_mode=="setup"?1:0).');">'.$str.'</a>';
	}

	/**
	 * [Describe function...]
	 *
	 * @param	[type]		$input: ...
	 * @param	[type]		$ln: ...
	 * @param	[type]		$comments: ...
	 * @param	[type]		$crop: ...
	 * @return	[type]		...
	 */
	function ext_formatTS($input, $ln, $comments=1, $crop=0)	{
		$input = ereg_replace('^[^'.chr(10).']*.','',$input);
		$input = chop($input);
		$cArr = explode(chr(10),$input);

		reset($cArr);
		$n = ceil(log10(count($cArr)+$this->ext_lineNumberOffset));
		$lineNum='';
		while(list($k,$v)=each($cArr))	{
			$lln=$k+$this->ext_lineNumberOffset+1;
			if ($ln)	$lineNum = $this->ext_lnBreakPointWrap($lln,str_replace(' ','&nbsp;',sprintf('% '.$n.'d',$lln))).':   ';
			$v=htmlspecialchars($v);
			if ($crop)	{$v=$this->ext_fixed_lgd($v,($ln?71:77));}
			$cArr[$k] = $lineNum.str_replace(' ','&nbsp;',$v);

			$firstChar = substr(trim($v),0,1);
			if ($firstChar=='[')	{
				$cArr[$k] = '<font color="green"><b>'.$cArr[$k].'</b></font>';
			} elseif ($firstChar=='/' || $firstChar=='#')	{
				if ($comments)	{
					$cArr[$k] = '<span class="typo3-dimmed">'.$cArr[$k].'</span>';
				} else {
					unset($cArr[$k]);
				}
			}


		}
		$output = implode($cArr, '<br />').'<br />';
		return $output;
	}

	/**
	 * [Describe function...]
	 *
	 * @param	[type]		$id: ...
	 * @param	[type]		$template_uid: ...
	 * @return	[type]		...
	 */
	function ext_getFirstTemplate($id,$template_uid=0)		{
			// Query is taken from the runThroughTemplates($theRootLine) function in the parent class.
		if (intval($id))	{
			if ($template_uid)	{
				$addC = ' AND uid='.$template_uid;
			}
			$res = $GLOBALS['TYPO3_DB']->exec_SELECTquery('*', 'sys_template', 'pid='.intval($id).$addC.' '.$this->whereClause, '', 'sorting', '1');
			$row = $GLOBALS['TYPO3_DB']->sql_fetch_assoc($res);
			t3lib_BEfunc::workspaceOL('sys_template',$row);
			$GLOBALS['TYPO3_DB']->sql_free_result($res);
			return $row;	// Returns the template row if found.
		}
	}

	/**
	 * [Describe function...]
	 *
	 * @param	[type]		$id: ...
	 * @return	[type]		...
	 */
	function ext_getAllTemplates($id)		{
			// Query is taken from the runThroughTemplates($theRootLine) function in the parent class.
		if (intval($id))	{
			$outRes=array();
			$res = $GLOBALS['TYPO3_DB']->exec_SELECTquery('*', 'sys_template', 'pid='.intval($id).' '.$this->whereClause, '', 'sorting');
			while($row = $GLOBALS['TYPO3_DB']->sql_fetch_assoc($res))	{
				t3lib_BEfunc::workspaceOL('sys_template',$row);
				if (is_array($row))		$outRes[] = $row;
			}
			$GLOBALS['TYPO3_DB']->sql_free_result($res);
			return $outRes;	// Returns the template rows in an array.
		}
	}

	/**
	 * This function compares the flattened constants (default and all).
	 * Returns an array with the constants from the whole template which may be edited by the module.
	 *
	 * @param	[type]		$default: ...
	 * @return	[type]		...
	 */
	function ext_compareFlatSetups($default)	{
		$editableComments=array();
		reset($this->flatSetup);
		while(list($const,$value)=each($this->flatSetup))	{
			if (substr($const,-2)!='..' && isset($this->flatSetup[$const.'..']))	{
				$comment = trim($this->flatSetup[$const.'..']);
				$c_arr = explode(chr(10),$comment);
				while(list($k,$v)=each($c_arr))	{
					$line=trim(ereg_replace('^[#\/]*','',$v));
					if ($line)	{
						$parts = explode(';', $line);
						while(list(,$par)=each($parts))		{
							if (strstr($par,'='))	{
								$keyValPair =explode('=',$par,2);
								switch(trim(strtolower($keyValPair[0])))	{
									case 'type':
											// Type:
											/*
	int (range; low-high, list: item,item,item = selector),
	boolean (check),
	string (default),
	wrap,
	html-color ...,
	file
											*/
										$editableComments[$const]['type'] = trim($keyValPair[1]);
									break;
									case 'cat':
											// list of categories.
										$catSplit=explode('/',strtolower($keyValPair[1]));
										$editableComments[$const]['cat'] = trim($catSplit[0]);
										$catSplit[1]=trim($catSplit[1]);	// This is the subcategory. Must be a key in $this->subCategories[]. catSplit[2] represents the search-order within the subcat.
										if ($catSplit[1] && isset($this->subCategories[$catSplit[1]]))	{
											$editableComments[$const]['subcat_name']=$catSplit[1];
											$editableComments[$const]['subcat']=$this->subCategories[$catSplit[1]][1].'/'.$catSplit[1].'/'.trim($catSplit[2]).'z';
										} else {
											$editableComments[$const]['subcat']='x'.'/'.trim($catSplit[2]).'z';
										}
									break;
									case 'label':
											// label
										$editableComments[$const]['label'] = trim($keyValPair[1]);
									break;
								}
							}
						}
					}
				}
			}
			if (isset($editableComments[$const]))	{
				$editableComments[$const]['name']=$const;
				$editableComments[$const]['value']=trim($value);
				if (isset($default[$const]))	{
					$editableComments[$const]['default_value']=trim($default[$const]);
				}
			}
		}
		return $editableComments;
	}

	/**
	 * [Describe function...]
	 *
	 * @param	[type]		$editConstArray: ...
	 * @return	[type]		...
	 */
	function ext_categorizeEditableConstants($editConstArray)	{
		// Runs through the available constants and fills the $this->categories array with pointers and priority-info
		reset($editConstArray);
		while(list($constName,$constData)=each($editConstArray))	{
			if (!$constData['type']) {
				$constData['type']='string';
			}
			$cats = explode(',',$constData['cat']);
			reset($cats);
			while (list(,$theCat)=each($cats))	{		// if = only one category, while allows for many. We have agreed on only one category is the most basic way...
				$theCat=trim($theCat);
				if ($theCat)	{
					$this->categories[$theCat][$constName]=$constData['subcat'];
				}
			}
		}
	}

	/**
	 * [Describe function...]
	 *
	 * @return	[type]		...
	 */
	function ext_getCategoryLabelArray()	{
		// Returns array used for labels in the menu.
		$retArr = array();
		while(list($k,$v)=each($this->categories))	{
			if (count($v))	{
				$retArr[$k]=strtoupper($k).' ('.count($v).')';
			}
		}
		return $retArr;
	}

	/**
	 * [Describe function...]
	 *
	 * @param	[type]		$type: ...
	 * @return	[type]		...
	 */
	function ext_getTypeData($type)	{
		$retArr = array();
		$type=trim($type);
		if (!$type)	{
			$retArr['type']='string';
		} else {
			$m=strcspn ($type,' [');
			$retArr['type']=strtolower(substr($type,0,$m));
			if (t3lib_div::inList('int,options,file,boolean,offset,user', $retArr['type']))	{
				$p=trim(substr($type,$m));
				$reg = array();
				ereg('\[(.*)\]',$p,$reg);
				$p=trim($reg[1]);
				if ($p)	{
					$retArr['paramstr']=$p;
					switch($retArr['type'])	{
						case 'int':
							if (substr($retArr['paramstr'],0,1)=='-')	{
								$retArr['params']=t3lib_div::intExplode('-',substr($retArr['paramstr'],1));
								$retArr['params'][0]=intval('-'.$retArr['params'][0]);
							} else {
								$retArr['params']=t3lib_div::intExplode('-',$retArr['paramstr']);
							}
							$retArr['paramstr']=$retArr['params'][0].' - '.$retArr['params'][1];
						break;
						case 'options':
							$retArr['params']=explode(',',$retArr['paramstr']);
						break;
					}
				}
			}
		}
		return $retArr;
	}

	/**
	 * [Describe function...]
	 *
	 * @param	[type]		$category: ...
	 * @return	[type]		...
	 */
	function ext_getTSCE_config($category)	{
		$catConf=$this->setup['constants']['TSConstantEditor.'][$category.'.'];
		$out=array();
		if (is_array($catConf))	{
			reset($catConf);
			while(list($key,$val)=each($catConf))	{
				switch($key)	{
					case 'image':
						$out['imagetag'] = $this->ext_getTSCE_config_image($catConf['image']);
					break;
					case 'description':
					case 'bulletlist':
					case 'header':
						$out[$key] = $val;
					break;
					default:
						if (t3lib_div::testInt($key))	{
							$constRefs = explode(',',$val);
							reset($constRefs);
							while(list(,$const)=each($constRefs))	{
								$const=trim($const);
								if ($const && $const<=20)	{
									$out['constants'][$const].=$this->ext_getKeyImage($key);
								}
							}
						}
					break;
				}
			}
		}
		$this->helpConfig=$out;
	}

	/**
	 * [Describe function...]
	 *
	 * @param	[type]		$key: ...
	 * @return	[type]		...
	 */
	function ext_getKeyImage($key)	{
		return '<img src="'.$this->ext_localWebGfxPrefix.'gfx/'.$key.'.gif" align="top" hspace=2>';
	}

	/**
	 * [Describe function...]
	 *
	 * @param	[type]		$imgConf: ...
	 * @return	[type]		...
	 */
	function ext_getTSCE_config_image($imgConf)	{
		if (substr($imgConf,0,4)=='gfx/')	{
			$iFile=$this->ext_localGfxPrefix.$imgConf;
			$tFile=$this->ext_localWebGfxPrefix.$imgConf;
		} elseif (substr($imgConf,0,4)=='EXT:') {
			$iFile = t3lib_div::getFileAbsFileName($imgConf);
			if ($iFile)	{
				$f = substr($iFile,strlen(PATH_site));
				$tFile=$GLOBALS['BACK_PATH'].'../'.$f;
			}
		} else {
			$f = 'uploads/tf/'.$this->extractFromResources($this->setup['resources'],$imgConf);
			$iFile=PATH_site.$f;
			$tFile=$GLOBALS['BACK_PATH'].'../'.$f;
		}
		$imageInfo=@getImagesize($iFile);
		return '<img src="'.$tFile.'" '.$imageInfo[3].'>';
	}

	/**
	 * [Describe function...]
	 *
	 * @return	[type]		...
	 */
	function ext_resourceDims()	{
		if ($this->setup['resources'])	{
			$rArr=explode(',',$this->setup['resources']);
			while(list($c,$val)=each($rArr))	{
				$val=trim($val);
				$theFile = PATH_site.'uploads/tf/'.$val;
				if ($val && @is_file($theFile))	{
					$imgInfo = @getimagesize($theFile);
				}
				if (is_array($imgInfo))	{
					$this->resourceDimensions[$val]=' ('.$imgInfo[0].'x'.$imgInfo[1].')';
				}
			}
		}
		reset($this->dirResources);
		while(list($c,$val)=each($this->dirResources))	{
			$val=trim($val);
			$imgInfo = @getimagesize(PATH_site.$val);
			if (is_array($imgInfo))	{
				$this->resourceDimensions[$val]=' ('.$imgInfo[0].'x'.$imgInfo[1].')';
			}
		}
	}

	/**
	 * [Describe function...]
	 *
	 * @param	[type]		$path: ...
	 * @return	[type]		...
	 */
	function ext_readDirResources($path)	{
		$path=trim($path);
		if ($path && substr($path,0,10)=='fileadmin/')	{
			$path = ereg_replace('\/$','',$path);
			$this->readDirectory(PATH_site.$path);
		}
	}

	/**
	 * [Describe function...]
	 *
	 * @param	[type]		$path: ...
	 * @param	[type]		$type: ...
	 * @return	[type]		...
	 */
	function readDirectory($path,$type='file')	{
		if(@is_dir($path))	{
			$d = @dir($path);
			$tempArray=Array();
			if (is_object($d))	{
				while($entry=$d->read()) {
					if ($entry!='.' && $entry!='..')	{
						$wholePath = $path.'/'.$entry;		// Because of odd PHP-error where  <BR>-tag is sometimes placed after a filename!!
						if (@file_exists($wholePath) && (!$type || filetype($wholePath)==$type))	{
							$fI = t3lib_div::split_fileref($wholePath);
							$this->dirResources[]=substr($wholePath,strlen(PATH_site));
						}
					}
				}
				$d->close();
			}
		}
	}

	/**
	 * [Describe function...]
	 *
	 * @param	[type]		$params: ...
	 * @return	[type]		...
	 */
	function ext_fNandV($params)	{
		$fN='data['.$params['name'].']';
		$fV=$params['value'];
		if (ereg('^{[\$][a-zA-Z0-9\.]*}$',trim($fV),$reg))	{		// Values entered from the constantsedit cannot be constants!	230502; removed \{ and set {
			$fV='';
		}
		$fV=htmlspecialchars($fV);

		return array($fN,$fV,$params);
	}

	/**
	 * This functions returns the HTML-code that creates the editor-layout of the module.
	 *
	 * @param	[type]		$theConstants: ...
	 * @param	[type]		$category: ...
	 * @return	[type]		...
	 */
	function ext_printFields($theConstants,$category)	{
		reset($theConstants);
		$output='<script type="text/javascript" src="'.$GLOBALS['BACK_PATH'].'js/constantEditor.js"></script>
		';
		$subcat='';
		if (is_array($this->categories[$category]))	{

			$help=$this->helpConfig;
			$this->rArr=explode(',',$this->setup['resources'].','.implode($this->dirResources,','));

			if (!$this->doNotSortCategoriesBeforeMakingForm) asort($this->categories[$category]);
			while(list($name,$type)=each($this->categories[$category]))	{
				$params = $theConstants[$name];
				if (is_array($params))	{
					if ($subcat!=$params['subcat_name'])	{
						$subcat=$params['subcat_name'];
						$subcat_name = $params['subcat_name'] ? $this->subCategories[$params['subcat_name']][0] : 'Others';

						$output.='<h2 class="typo3-tstemplate-ceditor-subcat">'.$subcat_name.'</h2>';
					}

					$label=$GLOBALS['LANG']->sL($params['label']);
					$label_parts = explode(':',$label,2);
					if (count($label_parts)==2)	{
						$head=trim($label_parts[0]);
						$body=trim($label_parts[1]);
					} else {
						$head=trim($label_parts[0]);
						$body='';
					}
					if (strlen($head)>35)	{
						if (!$body) {$body=$head;}
						$head=t3lib_div::fixed_lgd_cs($head,35);
					}
					$typeDat=$this->ext_getTypeData($params['type']);
					$checked='';
					$p_field='';
					$raname = substr(md5($params['name']),0,10);
					$aname='\''.$raname.'\'';

					list($fN,$fV,$params)=$this->ext_fNandV($params);

					switch($typeDat['type'])	{
						case 'int':
						case 'int+':
							$p_field='<input id="'.$fN.'" type="text" name="'.$fN.'" value="'.$fV.'"'.$GLOBALS['TBE_TEMPLATE']->formWidth(5).' onChange="uFormUrl('.$aname.')" />';
							if ($typeDat['paramstr'])	{
								$p_field.=' Range: '.$typeDat['paramstr'];
							} elseif ($typeDat['type']=='int+') {
								$p_field.=' Range: 0 - ';
							} else {
								$p_field.=' (Integer)';
							}
						break;
						case 'color':
							$colorNames=explode(',',','.$this->HTMLcolorList);
							$p_field='';
							while(list(,$val)=each($colorNames))	{
								$sel='';
								if ($val==strtolower($params['value'])) {
									$sel = ' selected';
								}
								$p_field.='<option value="'.htmlspecialchars($val).'"'.$sel.'>'.$val.'</option>';
							}
							$p_field='<select id="select-'.$fN.'" rel="'.$fN.'" name="C'.$fN.'" class="typo3-tstemplate-ceditor-color-select" onChange="uFormUrl('.$aname.');">'.$p_field.'</select>';

							$p_field.='<input type="text" id="input-'.$fN.'" rel="'.$fN.'" name="'.$fN.'" class="typo3-tstemplate-ceditor-color-input" value="'.$fV.'"'.$GLOBALS['TBE_TEMPLATE']->formWidth(7).' onChange="uFormUrl('.$aname.')" />';
						break;
						case 'wrap':
							$wArr = explode('|',$fV);
							$p_field='<input type="text" id="'.$fN.'" name="'.$fN.'" value="'.$wArr[0].'"'.$GLOBALS['TBE_TEMPLATE']->formWidth(29).' onChange="uFormUrl('.$aname.')" />';
							$p_field.=' | ';
							$p_field.='<input type="text" name="W'.$fN.'" value="'.$wArr[1].'"'.$GLOBALS['TBE_TEMPLATE']->formWidth(15).' onChange="uFormUrl('.$aname.')" />';
						break;
						case 'offset':
							$wArr = explode(',',$fV);
							$labels = t3lib_div::trimExplode(',',$typeDat['paramstr']);
							$p_field=($labels[0]?$labels[0]:'x').':<input type="text" name="'.$fN.'" value="'.$wArr[0].'"'.$GLOBALS['TBE_TEMPLATE']->formWidth(4).' onChange="uFormUrl('.$aname.')" />';
							$p_field.=' , ';
							$p_field.=($labels[1]?$labels[1]:'y').':<input type="text" name="W'.$fN.'" value="'.$wArr[1].'"'.$GLOBALS['TBE_TEMPLATE']->formWidth(4).' onChange="uFormUrl('.$aname.')" />';
							for ($aa=2;$aa<count($labels);$aa++)	{
								if ($labels[$aa])	{
									$p_field.=' , '.$labels[$aa].':<input type="text" name="W'.$aa.$fN.'" value="'.$wArr[$aa].'"'.$GLOBALS['TBE_TEMPLATE']->formWidth(4).' onChange="uFormUrl('.$aname.')" />';
								} else {
									$p_field.='<input type="hidden" name="W'.$aa.$fN.'" value="'.$wArr[$aa].'" />';
								}
							}
						break;
						case 'options':
							if (is_array($typeDat['params']))	{
								$p_field='';
								while(list(,$val)=each($typeDat['params']))	{
									$vParts = explode('=',$val,2);
									$label = $vParts[0];
									$val = isset($vParts[1]) ? $vParts[1] : $vParts[0];

									// option tag:
									$sel='';
									if ($val==$params['value'])	{
										$sel=' selected';
									}
									$p_field.='<option value="'.htmlspecialchars($val).'"'.$sel.'>'.$GLOBALS['LANG']->sL($label).'</option>';
								}
								$p_field='<select id="'.$fN.'" name="'.$fN.'" onChange="uFormUrl('.$aname.')">'.$p_field.'</select>';
							}
						break;
						case 'boolean':
							$p_field='<input type="hidden" name="'.$fN.'" value="0" />';
							$sel='';
							if ($fV)	{
								$sel=' checked';
							}
							$p_field.='<input id="'.$fN.'" type="checkbox" name="'.$fN.'" value="'.($typeDat['paramstr']?$typeDat['paramstr']:1).'"'.$sel.' onClick="uFormUrl('.$aname.')" />';
						break;
						case 'comment':
							$p_field='<input type="hidden" name="'.$fN.'" value="#" />';
							$sel='';
							if (!$fV)	{
								$sel=' checked';
							}
							$p_field.='<input id="'.$fN.'" type="checkbox" name="'.$fN.'" value=""'.$sel.' onClick="uFormUrl('.$aname.')" />';
						break;
						case 'file':
							$p_field='<option value=""></option>';
							$theImage='';
							$selectThisFile = $this->extractFromResources($this->setup['resources'],$params['value']);
							if ($params['value'] && !$selectThisFile)	{
								if (in_array($params['value'],$this->dirResources))	{
									$selectThisFile=$params['value'];
								}
							}
							// extensionlist
							$extList = $typeDat['paramstr'];
							$p_field='<option value="">('.$extList.')</option>';
							if ($extList=='IMAGE_EXT')	{
								$extList = $GLOBALS['TYPO3_CONF_VARS']['GFX']['imagefile_ext'];
							}
							reset($this->rArr);
							$onlineResourceFlag=$this->ext_defaultOnlineResourceFlag;

							while(list($c,$val)=each($this->rArr))	{
								$val=trim($val);
								$fI=t3lib_div::split_fileref($val);
								if ($val && (!$extList || t3lib_div::inList($extList,$fI['fileext'])))	{
									if ($onlineResourceFlag<=0 && substr($fI['path'],0,10)=='fileadmin/')	{
										if ($onlineResourceFlag<0)	{
											$p_field.='<option value=""></option>';
										}
										$p_field.='<option value="">__'.$fI['path'].'__:</option>';
										$onlineResourceFlag=1;
									}
									$dims=$this->resourceDimensions[$val];
									$sel='';

									// Check if $params['value'] is in the list of resources.
									if ($selectThisFile && $selectThisFile==$val)	{
										$sel=' selected';
										if ($onlineResourceFlag<=0)	{
											$theImage=t3lib_BEfunc::thumbCode(array('resources'=>$selectThisFile),'sys_template','resources',$GLOBALS['BACK_PATH'],'');
										} else {
											$theImage=t3lib_BEfunc::thumbCode(array('resources'=>$fI['file']),'sys_template','resources',$GLOBALS['BACK_PATH'],'',$fI['path']);
										}
									}

									if ($onlineResourceFlag<=0)	{
										$onlineResourceFlag--;
										// Value is set with a *
										$val = $this->ext_setStar($val);
										$p_field.='<option value="'.htmlspecialchars($val).'"'.$sel.'>'.$val.$dims.'</option>';
									} else {
										$p_field.='<option value="'.htmlspecialchars($val).'"'.$sel.'>'.$fI['file'].$dims.'</option>';
									}
								}
							}

							if (trim($params['value']) && !$selectThisFile)	{
								$val = $params['value'];
								$p_field.='<option value=""></option>';
								$p_field.='<option value="'.htmlspecialchars($val).'" selected>'.$val.'</option>';
							}

							$p_field='<select id="'.$fN.'" name="'.$fN.'" onChange="uFormUrl('.$aname.')">'.$p_field.'</select>';
							$p_field.=$theImage;

							if (!$this->ext_noCEUploadAndCopying)	{
								// Copy a resource
								$copyFile = $this->extractFromResources($this->setup['resources'],$params['value']);
								if (!$copyFile)	{
									if ($params['value'])	{
										$copyFile=PATH_site.$this->ext_detectAndFixExtensionPrefix($params['value']);
									}
								} else {
									$copyFile='';
								}

								if ($copyFile && @is_file($copyFile))	{
									$p_field.='<img src="clear.gif" width="20" height="1" alt="" /><img'.t3lib_iconWorks::skinImg($GLOBALS['BACK_PATH'],'gfx/clip_copy.gif','width="12" height="12"').' border="0" alt="" /><input type="checkbox" name="_copyResource['.$params['name'].']" value="'.htmlspecialchars($copyFile).'" onClick="uFormUrl('.$aname.');if (this.checked) {alert(unescape(\''.rawurlencode(sprintf("This will make a copy of the current file, '%s'. Do you really want that?",$params['value'])).'\'));}" />';
								}

								// Upload?
								$p_field.='<br />';
								$p_field.='<input id="'.$fN.'" type="file" name="upload_'.$fN.'"'.$GLOBALS['TBE_TEMPLATE']->formWidth().' onChange="uFormUrl('.$aname.')" size="50" />';
							}
						break;
						case 'user':
							$userFunction       = $typeDat['paramstr'];
							$userFunctionParams = array('fieldName' => $fN, 'fieldValue' => $fV);
							$p_field            = t3lib_div::callUserFunction($userFunction, $userFunctionParams, $this, '');
						break;
						case 'small':
						default:
							$fwidth= $typeDat['type']=='small' ? 10 : 46;
							$p_field='<input id="'.$fN.'" type="text" name="'.$fN.'" value="'.$fV.'"'.$GLOBALS['TBE_TEMPLATE']->formWidth($fwidth).' onChange="uFormUrl('.$aname.')" />';
						break;
					}

					// Define default names and IDs
					$userTyposcriptID = 'userTS-'.$params['name'];
					$defaultTyposcriptID = 'defaultTS-'.$params['name'];
					$checkboxName = 'check['.$params['name'].']';
					$checkboxID = $checkboxName;

					// Handle type=color specially
					if ($typeDat['type']=='color' && substr($params['value'],0,2)!='{$')	{
						$color = '<div id="colorbox-'.$fN.'" class="typo3-tstemplate-ceditor-colorblock" style="background-color:'.$params['value'].';">&nbsp;</div>';
					} else {
						$color = '';
					}

					if (!$this->ext_dontCheckIssetValues) {

						/* Set the default styling options */
						if(isset($this->objReg[$params['name']])) {
							$checkboxValue = 'checked';
							$userTyposcriptStyle = '';
							$defaultTyposcriptStyle = 'style="display:none;"';
						} else {
							$checkboxValue = '';
							$userTyposcriptStyle = 'style="display:none;"';
							$defaultTyposcriptStyle = '';
						}


						$deleteIconHTML = '<img class="typo3-tstemplate-ceditor-control undoIcon" '.t3lib_iconWorks::skinImg($GLOBALS['BACK_PATH'], 'gfx/undo.gif').' alt="Revert to default Constant" title="Revert to default Constant" rel="'.$params['name'].'" />';
						$editIconHTML 	= '<img class="typo3-tstemplate-ceditor-control editIcon" '.t3lib_iconWorks::skinImg($GLOBALS['BACK_PATH'], 'gfx/edit2.gif').' alt="Edit this Constant" title="Edit this Constant" rel="'.$params['name'].'" />';
						$constantCheckbox = '<input type="hidden" name="'.$checkboxName.'" id="'.$checkboxID.'" value="'.$checkboxValue.'"/>';

						// If there's no default value for the field, use a static label.
						if(!$params['default_value']) {
							$params['default_value'] = '[Empty]';
						}

						$constantDefaultRow='<div class="typo3-tstemplate-ceditor-row" id="'.$defaultTyposcriptID.'" '.$defaultTyposcriptStyle.'>'.$editIconHTML.htmlspecialchars($params['default_value']).$color.'</div>';
					}

					$constantEditRow = '<div class="typo3-tstemplate-ceditor-row" id="'.$userTyposcriptID.'" '.$userTyposcriptStyle.'>'.$deleteIconHTML.$p_field.$color.'</div>';

					$constantLabel = '<dt class="typo3-tstemplate-ceditor-label">'.htmlspecialchars($head).'</dt>';
					$constantName = '<dt class="typo3-dimmed">['.$params['name'].']</dt>';
					$constantDescription = $body ? '<dd>'.htmlspecialchars($body).'</dd>' : '';
					$constantData = '<dd>'.$constantCheckbox.$constantEditRow.$constantDefaultRow.'</dd>';

					$output.='<a name="'.$raname.'"></a>'.$help['constants'][$params['name']];
					$output.='<dl class="typo3-tstemplate-ceditor-constant">'.$constantLabel.$constantName.$constantDescription.$constantData.'</dl>';
				} else {
					debug('Error. Constant did not exist. Should not happen.');
				}
			}
		}
		return $output;
	}












	/***************************
	 *
	 * Processing input values
	 *
	 ***************************/

	/**
	 * @param	[type]		$constants: ...
	 * @return	[type]		...
	 */
	function ext_regObjectPositions($constants)	{
			// This runs through the lines of the constants-field of the active template and registers the constants-names and linepositions in an array, $this->objReg
		$this->raw = explode(chr(10),$constants);
		$this->rawP=0;

		$this->objReg=array();		// resetting the objReg if the divider is found!!
		$this->ext_regObjects('');
	}

	/**
	 * [Describe function...]
	 *
	 * @param	[type]		$pre: ...
	 * @return	[type]		...
	 */
	function ext_regObjects($pre)	{
			// works with regObjectPositions. "expands" the names of the TypoScript objects
		while (isset($this->raw[$this->rawP]))	{
			$line = ltrim($this->raw[$this->rawP]);
			if (strstr($line,$this->edit_divider))	{
				$this->objReg=array();		// resetting the objReg if the divider is found!!
			}
			$this->rawP++;
			if ($line)	{
				if (substr($line,0,1)=='[')	{
//					return $line;
				} elseif (strcspn($line,'}#/')!=0)	{
					$varL = strcspn($line,' {=<');
					$var=substr($line,0,$varL);
					$line = ltrim(substr($line,$varL));
					switch(substr($line,0,1))	{
						case '=':
							$this->objReg[$pre.$var]=$this->rawP-1;
						break;
						case '{':
							$this->ext_inBrace++;
							$this->ext_regObjects($pre.$var.'.');
						break;
					}
					$this->lastComment='';
				} elseif (substr($line,0,1)=='}')	{
					$this->lastComment='';
					$this->ext_inBrace--;
					if ($this->ext_inBrace<0)	{
						$this->ext_inBrace=0;
					} else {
						break;
					}
				}
			}
		}
	}

	/**
	 * [Describe function...]
	 *
	 * @param	[type]		$key: ...
	 * @param	[type]		$var: ...
	 * @return	[type]		...
	 */
	function ext_putValueInConf($key, $var)	{
			// Puts the value $var to the TypoScript value $key in the current lines of the templates.
			// If the $key is not found in the template constants field, a new line is inserted in the bottom.
		$theValue = ' '.trim($var);
		if (isset($this->objReg[$key]))	{
			$lineNum = $this->objReg[$key];
			$parts = explode('=',$this->raw[$lineNum],2);
			if (count($parts)==2)	{
				$parts[1]= $theValue;
			}
			$this->raw[$lineNum]=implode($parts,'=');
		} else {
			$this->raw[]=$key.' ='.$theValue;
		}
		$this->changed=1;
	}

	/**
	 * [Describe function...]
	 *
	 * @param	[type]		$key: ...
	 * @return	[type]		...
	 */
	function ext_removeValueInConf($key)	{
			// Removes the value in the configuration
		if (isset($this->objReg[$key]))	{
			$lineNum = $this->objReg[$key];
			unset($this->raw[$lineNum]);
		}
		$this->changed=1;
	}

	/**
	 * [Describe function...]
	 *
	 * @param	[type]		$arr: ...
	 * @param	[type]		$settings: ...
	 * @return	[type]		...
	 */
	function ext_depthKeys($arr,$settings)	{
		reset($arr);
		$tsbrArray=array();
		while(list($theK,$theV)=each($arr))	{
			$theKeyParts = explode('.',$theK);
			$depth='';
			$c=count($theKeyParts);
			$a=0;
			while(list(,$p)=each($theKeyParts))	{
				$a++;
				$depth.=($depth?'.':'').$p;
				$tsbrArray[$depth]= ($c==$a) ? $theV : 1;
			}
		}
			// Modify settings
		reset($tsbrArray);
		while(list($theK,$theV)=each($tsbrArray))	{
			if ($theV)	{
				$settings[$theK] = 1;
			} else {
				unset($settings[$theK]);
			}
		}
		return $settings;
	}

	/**
	 * [Describe function...]
	 *
	 * @param	[type]		$http_post_vars: ...
	 * @param	[type]		$http_post_files: ...
	 * @param	[type]		$theConstants: ...
	 * @param	[type]		$tplRow: ...
	 * @return	[type]		...
	 */
	function ext_procesInput($http_post_vars,$http_post_files,$theConstants,$tplRow)	{
		$data=$http_post_vars['data'];
		$check=$http_post_vars['check'];
		$copyResource=$http_post_vars['_copyResource'];
		$Wdata=$http_post_vars['Wdata'];
		$W2data=$http_post_vars['W2data'];
		$W3data=$http_post_vars['W3data'];
		$W4data=$http_post_vars['W4data'];
		$W5data=$http_post_vars['W5data'];

		if (is_array($data))	{
			reset($data);
			while(list($key,$var)=each($data))	{
				if (isset($theConstants[$key]))	{
					if ($this->ext_dontCheckIssetValues || isset($check[$key]))	{		// If checkbox is set, update the value
						list($var) = explode(chr(10),$var);	// exploding with linebreak, just to make sure that no multiline input is given!
						$typeDat=$this->ext_getTypeData($theConstants[$key]['type']);
						switch($typeDat['type'])	{
							case 'int':
								if ($typeDat['paramstr'])	{
									$var=t3lib_div::intInRange($var,$typeDat['params'][0],$typeDat['params'][1]);
								} else {
									$var=intval($var);
								}
							break;
							case 'int+':
								$var = max(0, intval($var));
								break;
							case 'color':
								$col=array();
								if($var && !t3lib_div::inList($this->HTMLcolorList,strtolower($var)))	{
									$var = ereg_replace('[^A-Fa-f0-9]*','',$var);
									$useFullHex = strlen($var) > 3;

									$col[]=HexDec(substr($var,0,1));
									$col[]=HexDec(substr($var,1,1));
									$col[]=HexDec(substr($var,2,1));

									if($useFullHex) {
										$col[]=HexDec(substr($var,3,1));
										$col[]=HexDec(substr($var,4,1));
										$col[]=HexDec(substr($var,5,1));
									}

									$var = substr('0'.DecHex($col[0]),-1).substr('0'.DecHex($col[1]),-1).substr('0'.DecHex($col[2]),-1);
									if($useFullHex) {
										$var .= substr('0'.DecHex($col[3]),-1).substr('0'.DecHex($col[4]),-1).substr('0'.DecHex($col[5]),-1);
									}

									$var = '#'.strtoupper($var);
								}
							break;
							case 'comment':
								if ($var)	{
									$var='#';
								} else {
									$var='';
								}
							break;
							case 'wrap':
								if (isset($Wdata[$key]))	{
									$var.='|'.$Wdata[$key];
								}
							break;
							case 'offset':
								if (isset($Wdata[$key]))	{
									$var=intval($var).','.intval($Wdata[$key]);
									if (isset($W2data[$key]))	{
										$var.=','.intval($W2data[$key]);
										if (isset($W3data[$key]))	{
											$var.=','.intval($W3data[$key]);
											if (isset($W4data[$key]))	{
												$var.=','.intval($W4data[$key]);
												if (isset($W5data[$key]))	{
													$var.=','.intval($W5data[$key]);
												}
											}
										}
									}
								}
							break;
							case 'boolean':
								if ($var)	{
									$var = $typeDat['paramstr'] ? $typeDat['paramstr'] : 1;
								}
							break;
							case 'file':
								if (!$this->ext_noCEUploadAndCopying)	{
									if ($http_post_files['upload_data']['name'][$key] && $http_post_files['upload_data']['tmp_name'][$key]!='none')	{
										$var = $this->upload_copy_file(
											$typeDat,
											$tplRow,
											trim($http_post_files['upload_data']['name'][$key]),
											$http_post_files['upload_data']['tmp_name'][$key]
										);
									}
									if ($copyResource[$key])	{
										$var = $this->upload_copy_file(
											$typeDat,
											$tplRow,
											basename($copyResource[$key]),
											$copyResource[$key]
										);
									}
								}
							break;
						}
						if ($this->ext_printAll || strcmp($theConstants[$key]['value'],$var))	{
							$this->ext_putValueInConf($key, $var);		// Put value in, if changed.
						}
						unset($check[$key]);		// Remove the entry because it has been "used"
					} else {
						$this->ext_removeValueInConf($key);
					}
				}
			}
		}
			// Remaining keys in $check indicates fields that are just clicked "on" to be edited. Therefore we get the default value and puts that in the template as a start...
		if (!$this->ext_dontCheckIssetValues && is_array($check))	{
			reset($check);
			while(list($key,$var)=each($check))	{
				if (isset($theConstants[$key]))	{
					$dValue = $theConstants[$key]['default_value'];
					$this->ext_putValueInConf($key, $dValue);
				}
			}
		}
	}

	/**
	 * [Describe function...]
	 *
	 * @param	[type]		$typeDat: ...
	 * @param	[type]		$tplRow: ...
	 * @param	[type]		$theRealFileName: ...
	 * @param	[type]		$tmp_name: ...
	 * @return	[type]		...
	 */
	function upload_copy_file($typeDat,&$tplRow,$theRealFileName,$tmp_name)	{

			// extensions
		$extList = $typeDat['paramstr'];
		if ($extList=='IMAGE_EXT')	{
			$extList = $GLOBALS['TYPO3_CONF_VARS']['GFX']['imagefile_ext'];
		}
		$fI=t3lib_div::split_fileref($theRealFileName);
		if ($theRealFileName && (!$extList || t3lib_div::inList($extList,$fI['fileext'])))	{
			$tmp_upload_name = t3lib_div::upload_to_tempfile($tmp_name);	// If there is an uploaded file, move it for the sake of safe_mode.

				// Saving resource
			$alternativeFileName=array();
			$alternativeFileName[$tmp_upload_name] = $theRealFileName;
				// Making list of resources
			$resList = $tplRow['resources'];
			$resList = $tmp_upload_name.','.$resList;
			$resList=implode(t3lib_div::trimExplode(',',$resList,1),',');
				// Making data-array
			$saveId = $tplRow['_ORIG_uid'] ? $tplRow['_ORIG_uid'] : $tplRow['uid'];

			$recData=array();
			$recData['sys_template'][$saveId]['resources'] = $resList;
				// Saving
			$tce = t3lib_div::makeInstance('t3lib_TCEmain');
			$tce->stripslashes_values=0;
			$tce->alternativeFileName = $alternativeFileName;
			$tce->start($recData,Array());
			$tce->process_datamap();

			t3lib_div::unlink_tempfile($tmp_upload_name);

			$tmpRow = t3lib_BEfunc::getRecordWSOL('sys_template',$saveId,'resources');

			$tplRow['resources'] = $tmpRow['resources'];

				// Setting the value
			$var = $this->ext_setStar($theRealFileName);
		}
		return $var;
	}

	/**
	 * [Describe function...]
	 *
	 * @param	[type]		$id: ...
	 * @param	[type]		$perms_clause: ...
	 * @return	[type]		...
	 */
	function ext_prevPageWithTemplate($id,$perms_clause)	{
		$rootLine = t3lib_BEfunc::BEgetRootLine($id,$perms_clause?' AND '.$perms_clause:'');
		reset($rootLine);
		while(list(,$p)=each($rootLine))	{
			if ($this->ext_getFirstTemplate($p['uid']))	{
				return $p;
			}
		}
	}

	/**
	 * [Describe function...]
	 *
	 * @param	[type]		$val: ...
	 * @return	[type]		...
	 */
	function ext_setStar($val)	{
		$fParts = explode('.',strrev($val),2);
		$val=ereg_replace('_[0-9][0-9]$','',strrev($fParts[1])).'*.'.strrev($fParts[0]);
		return $val;
	}

	/**
	 * [Describe function...]
	 *
	 * @param	[type]		$value: ...
	 * @return	[type]		...
	 */
	function ext_detectAndFixExtensionPrefix($value)	{
		if (substr($value,0,4)=='EXT:')	{
			$parts = explode('/',substr($value,4),2);

			$extPath = t3lib_extMgm::siteRelPath($parts[0]);
			$value = $extPath.$parts[1];
			return $value;
		} else {
			return $value;
		}
	}
}


if (defined('TYPO3_MODE') && $TYPO3_CONF_VARS[TYPO3_MODE]['XCLASS']['t3lib/class.t3lib_tsparser_ext.php'])	{
	include_once($TYPO3_CONF_VARS[TYPO3_MODE]['XCLASS']['t3lib/class.t3lib_tsparser_ext.php']);
}
?>
